﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.TextMining.Ontologies
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class TermRelationInstruction:InstructionBase
    {
        #region props
        private string _ConnStr;
        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._ConnStr;
            }
            set
            {
                this._ConnStr = value;
            }
        }

        private string _FTTableName;
        /// <summary></summary>
        public string FTTableName
        {
            get
            {
                return this._FTTableName;
            }
            set
            {
                this._FTTableName = value;
            }
        }

        private string _KeyField;
        /// <summary></summary>
        public string KeyField
        {
            get
            {
                return this._KeyField;
            }
            set
            {
                this._KeyField = value;
            }
        }

        private Dictionary<string,double> _TextFieldWeights;
        /// <summary></summary>
        public Dictionary<string,double> TextFieldWeights
        {
            get
            {
                return this._TextFieldWeights;
            }
            set
            {
                this._TextFieldWeights = value;
            }
        }

        private double _DocDistanceThreshold;
        /// <summary></summary>
        public double DocDistanceThreshold
        {
            get
            {
                return this._DocDistanceThreshold;
            }
            set
            {
                this._DocDistanceThreshold = value;
            }
        }

        private double _TermWeightThreshold;
        /// <summary></summary>
        public double TermWeightThreshold
        {
            get
            {
                return this._TermWeightThreshold;
            }
            set
            {
                this._TermWeightThreshold = value;
            }
        }

        private string _TermRelationConnStr;
        /// <summary></summary>
        public string TermRelationConnStr
        {
            get
            {
                return this._TermRelationConnStr;
            }
            set
            {
                this._TermRelationConnStr = value;
            }
        }

        private string _TermRelationTable;
        /// <summary></summary>
        public string TermRelationTable
        {
            get
            {
                return this._TermRelationTable;
            }
            set
            {
                this._TermRelationTable = value;
            }
        }

        private string _TermIDField;
        /// <summary></summary>
        public string TermIDField
        {
            get
            {
                return this._TermIDField;
            }
            set
            {
                this._TermIDField = value;
            }
        }

        private string _TermPhraseField;
        /// <summary></summary>
        public string TermPhraseField
        {
            get
            {
                return this._TermPhraseField;
            }
            set
            {
                this._TermPhraseField = value;
            }
        }

        private string _NeighborTermIDField;
        /// <summary></summary>
        public string NeighborTermIDField
        {
            get
            {
                return this._NeighborTermIDField;
            }
            set
            {
                this._NeighborTermIDField = value;
            }
        }

        private string _TermDistanceField;
        /// <summary></summary>
        public string TermDistanceField
        {
            get
            {
                return this._TermDistanceField;
            }
            set
            {
                this._TermDistanceField = value;
            }
        }
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        public TermRelationInstruction():base(Guid.Empty, Guid.Empty)
        {
            this._ConnStr = string.Empty;
            this._FTTableName = string.Empty;
            this._KeyField = string.Empty;
            this.TextFieldWeights=new Dictionary<string, double>();
            this._DocDistanceThreshold = 0.3;
            this._TermWeightThreshold = 2.5;
            this._TermRelationConnStr = string.Empty;
            this._TermRelationTable = string.Empty;
            this._TermIDField = string.Empty;
            this._TermPhraseField = string.Empty;
            this._NeighborTermIDField = string.Empty;
            this._TermDistanceField = string.Empty;
        }

        /// <summary>
        /// constructor, all derived class must call default constructor to initialize
        /// default settings.
        /// </summary>
        public TermRelationInstruction(Guid componentID, Guid jobTicketID,
            string connStr, string ftTbl, string keyField, 
            Dictionary<string,double> txtFieldWeights,
            double docDistanceThreshold, double termWeightThreshold,
            string tgtConnStr, string relationTbl, 
            string termIDField, string neighborTermIDField,
            string termPhraseField, string distanceField) 
            : base(componentID, jobTicketID)
        {
            this._ConnStr = connStr;
            this._FTTableName = ftTbl;
            this._KeyField = keyField;
            this._TextFieldWeights = txtFieldWeights;
            this._DocDistanceThreshold = docDistanceThreshold;
            this._TermWeightThreshold = termWeightThreshold;

            this._TermRelationConnStr = tgtConnStr;
            this._TermRelationTable = relationTbl;
            this._TermIDField = termIDField;
            this._TermPhraseField = termPhraseField;
            this._NeighborTermIDField = neighborTermIDField;
            this._TermDistanceField = distanceField;
        }
        #endregion

        #region Overrides of InstructionBase
        /// <summary>
        /// serialize settings to xml
        /// the function below is mainly for storing into database as serialized form instead of string
        /// </summary>
        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcConnStr",this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"FTTable",this.FTTableName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "FTKeyField",this.KeyField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DocDistanceThreshold",this.DocDistanceThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TermWeightThreshold",this.TermWeightThreshold.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtConnStr",this.TermRelationConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"RelationTable",this.TermRelationTable);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TermIDField",this.TermIDField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TermPhrase", this.TermPhraseField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "NeighborTermIDField",this.NeighborTermIDField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DistanceField",this.TermDistanceField);

            if(this.TextFieldWeights !=null && this.TextFieldWeights.Count>0)
            {
                XmlNode txtFieldNodes = XmlDataUtil.AddElement(ref xDoc, xNode, "TextFields");
                foreach(string txtFieldName in this.TextFieldWeights.Keys)
                {
                    XmlNode txtNode = XmlDataUtil.AddElement(ref xDoc, txtFieldNodes, "TextField");
                    XmlDataUtil.UpdateAttribute(ref xDoc, txtNode, "FieldName",txtFieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, txtNode, "Weight",this.TextFieldWeights[txtFieldName].ToString());
                }
            }

            return xNode;
        }

        /// <summary>
        /// instantiated from xml
        /// "&lt;Instructions&gt;&lt;Instruction&gt;&lt;/Instruction&gt;&lt;/Instruction&gt;", must
        /// instantiate from first child of root node
        /// </summary>
        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                TermRelationInstruction instruction = new TermRelationInstruction();
                instruction.OwnerComponentID = new Guid(XmlDataUtil.GetAttributeValue(xNode, "ComponentID", Guid.NewGuid().ToString()));
                instruction.OwnerWorkerInstanceID = new Guid(XmlDataUtil.GetAttributeValue(xNode, "WorkerID", Guid.NewGuid().ToString()));
                instruction.SubmitTime = DateTime.Parse(XmlDataUtil.GetAttributeValue(xNode, "SubmitTime", TimeUtil.DbMinTime.ToString()));
                instruction.StartTime = DateTime.Parse(XmlDataUtil.GetAttributeValue(xNode, "StartTime", TimeUtil.DbMinTime.ToString()));

                instruction.ConnStr = XmlDataUtil.GetAttributeValue(xNode, "SrcConnStr", "");
                instruction.FTTableName = XmlDataUtil.GetAttributeValue(xNode, "FTTable", "");
                instruction.KeyField = XmlDataUtil.GetAttributeValue(xNode, "FTKeyField", "");
                instruction.DocDistanceThreshold =double.Parse(XmlDataUtil.GetAttributeValue(xNode, "DocDistanceThreshold", "0.3"));
                instruction.TermWeightThreshold = double.Parse(XmlDataUtil.GetAttributeValue(xNode, "TermWeightThreshold", "2.5"));

                instruction.TermRelationConnStr = XmlDataUtil.GetAttributeValue(xNode, "TgtConnStr", "");
                instruction.TermRelationTable = XmlDataUtil.GetAttributeValue(xNode, "RelationTable", "");
                instruction.TermIDField = XmlDataUtil.GetAttributeValue(xNode, "TermIDField", "");
                instruction.TermPhraseField = XmlDataUtil.GetAttributeValue(xNode, "TermPhrase", "");
                instruction.NeighborTermIDField = XmlDataUtil.GetAttributeValue(xNode, "NeighborTermIDField", "");
                instruction.TermDistanceField = XmlDataUtil.GetAttributeValue(xNode, "DistanceField", "");

                XmlNodeList txtNodes = xNode.SelectNodes("TextFields/TextFields");
                instruction.TextFieldWeights=new Dictionary<string, double>();
                if(txtNodes !=null && txtNodes.Count>0)
                {
                    foreach(XmlNode txtNode in txtNodes)
                    {
                        string fieldName = XmlDataUtil.GetAttributeValue(txtNode, "FieldName", "");
                        double weight = double.Parse(XmlDataUtil.GetAttributeValue(txtNode, "Weight", "1"));
                        instruction.TextFieldWeights.Add(fieldName, weight);
                    }
                }

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate component: invalid type specified in xml node");
            }
        }

        #endregion
    }
}
